import socket
from Helper import *
import threading
import Device

clientList = []
threadList = []
# TODO:通道号改为0，1
channel_1 = Device.Channel(0)
channel_2 = Device.Channel(1)

socketSendLock = threading.Lock()

def run(ip="0.0.0.0", port=8000):
    sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sk.bind((ip, port))
    sk.listen(5)
    log("Service is running...", INFO)
    serverStart(sk)

def serverStart(sk):
    # 将共享内存中的包发送出去
    getMemThread_1 = threading.Thread(target=channel_1.getMem)
    getMemThread_1.start()
    channel_1.memGetPackageEvent.methodHandler.append(recvLINDataProcessor)
    getMemThread_2 = threading.Thread(target=channel_2.getMem)
    getMemThread_2.start()
    channel_2.memGetPackageEvent.methodHandler.append(recvLINDataProcessor)

    while True:
        log("Waiting for new client", INFO)
        client, clientInfo = sk.accept()
        log("Client" + str(clientInfo) + "connected")
        t = threading.Thread(target=clientService, args=(client,))
        t.start()
        clientList.append(client)
        threadList.append(t)

def clientService(client):
    while True:
        try:
            recvData = client.recv(1024)
        except:
            log("主机强制关闭连接", ERROR)
            break
        if len(recvData) == 0:
            log("Client has gone ... ")
            clientList.remove(client)
            break
        log("Recieved data: " + hexToStyledStr(recvData))
        # 初步判断是否是需要处理的包,需要处理几个包
        packList = packSplite(recvData, 0X68, 0X16)
        if packList == None:
            continue
        # 将不同命令的包放到不同处理器中
        for pack in packList:
            sendData = processorDistributor(pack)
            if sendData == None or sendData == "":
                continue
            else:
                socketSend(client, sendData)

    client.close()

def socketSend(sk, data):
    socketSendLock.acquire()
    log("Send data: " + hexToStyledStr(data), INFO)
    sk.send(data)
    socketSendLock.release()

def processorDistributor(data):
    dataLen = int.from_bytes(data[1: 3], byteorder='little')
    dataField = data[3: 3 + dataLen]
    # 该位置是决定包的传送方向
    # 1：从LIN转换器向PC传递的包 0：从PC向LIN转换器传递的包
    # 但是测试中发现，更改LIN波特率存在该位为1的情况，所以先不判断
    # if getBit(dataField[0], 7) != 0:
    #     return None
    if not dataValidation(data):
        return None
    cmd = getRangeBit(dataField[0], 5, 0)
    switch = {
        0x00: cmdConfirmProcessor,
        0x01: connectionProcessor,
        0x09: synTimeProcessor,
        0x1f: RS232BuadProcessor,
        0x10: recvLINDataProcessor,
        0x11: sendLINHeadProcessor,
        0x12: uploadLINDataProcessor,
        0x13: writeCtrlProcessor,
        0x14: LINEventProcessor,
        0x15: respDataLengthProcessor,
        0x16: LINBuadProcessor
    }
    method = switch.get(cmd, None)
    if method:
        return method(dataField)

def cmdConfirmProcessor(data):
    pass

def connectionProcessor(data):
    if data[1] != 0x6c:
        return None
    sendData = bytearray(b'\x81')
    sendData.extend(Device.BasicInfo.encode('ascii'))
    sendData.append(0x00)
    sendData.extend(Device.DeviceModel.encode('ascii'))
    sendData.append(0x00)
    sendData.extend(Device.SerialNum.encode('ascii'))
    sendData = dataGenerator(sendData)
    return sendData

def synTimeProcessor(data):
    pass

def RS232BuadProcessor(data):
    targetChannel = None
    if data[1] == 0:
        targetChannel = channel_1
    elif data[1] == 1:
        targetChannel = channel_2
    else:
        log("The channel you selected not been supported", ERROR)
        return None

    targetChannel.RS232Buad = int.from_bytes(data[1: 5], byteorder='little')
    sendData = dataGenerator(bytearray(b'\x80\x1f'))
    return dataGenerator(sendData)

def recvLINDataProcessor(channelNum, data):
    targetChannel = None
    if channelNum == 0:
        targetChannel = channel_1
    elif channelNum == 1:
        targetChannel = channel_2
    else:
        log("The channel you selected not been supported", ERROR)
        return None

    sendData = bytearray(b'\x90')
    sendData.append(channelNum)
    sendData.extend(targetChannel.getTimeStamp())
    sendData.append(0)  # 接受结果
    # TODO:这里默认报文ID都为1，正确方式应该是LIN标准报文形式决定ID
    sendData.append(1)  # 报文ID
    # 判断ID默认数据场长度是否与数据长度相同
    if targetChannel.IDDataLength[1] < data.packLen:
        sendData.append(data.packLen)
        sendData.extend(data.dataBuffer)
    else:
        emptyByte = bytearray(targetChannel.IDDataLength[1] - data.packLen)
        sendData.append(targetChannel.IDDataLength[1])
        sendData.extend(data.dataBuffer)
        sendData.extend(emptyByte)
    sendData = dataGenerator(sendData)
    for client in clientList:
        socketSend(client, sendData)
    return None

def sendLINHeadProcessor(data):
    # TODO：发送帧头
    # targetChannel = None
    # if data[1] == 0:
    #     targetChannel = device_1
    # elif data[1] == 1:
    #     targetChannel = device_2
    # else:
    #     log("The channel you selected not been supported", ERROR)
    #     return None
    # setMem(data)
    return None

def uploadLINDataProcessor(data):
    targetChannel = None
    if data[1] == 0:
        targetChannel = channel_1
    elif data[1] == 1:
        targetChannel = channel_2
    else:
        log("The channel you selected not been supported", ERROR)
        return None

    IDAmount = data[2]
    nextIDIndex = 3
    for i in range(IDAmount):
        dataFieldLen = data[nextIDIndex + 1]
        targetChannel.IDResponseData[data[nextIDIndex]] = data[nextIDIndex + 2: nextIDIndex + 2 + dataFieldLen]
        nextIDIndex += 2 + dataFieldLen

    return dataGenerator(bytearray(b'\x80\x12'))

def writeCtrlProcessor(data):
    targetChannel = None
    if data[1] == 0x00:
        targetChannel = channel_1
    elif data[1] == 0x01:
        targetChannel = channel_2
    else:
        log("The channel you selected not been supported", ERROR)
        return None

    if getBit(data[2], 7) == 0:
        targetChannel.isMainCtrl = getBit(data[2], 0)
        targetChannel.isSleep = getBit(data[2], 1)
        targetChannel.LINPolicyVer = getRangeBit(data[2], 3, 2)
        if getBit(data[2], 4) == 1:
            targetChannel.errorCount = 0
        targetChannel.SynTime = getBit(data[2], 5)

    sendData = bytearray(b'\x93')
    sendData.append(data[1])
    sendData.append(targetChannel.LINPolicyVer)
    sendData.extend(targetChannel.errorCount.to_bytes(2, byteorder='little'))
    sendData.extend(targetChannel.busBuad.to_bytes(4, byteorder='little'))
    return dataGenerator(sendData)

def LINEventProcessor(channelNum):
    targetChannel = None
    if channelNum == 0:
        targetChannel = channel_1
    elif channelNum == 1:
        targetChannel = channel_2
    else:
        log("The channel you selected not been supported", ERROR)
        return None
    sendData = bytearray(b'\x94')
    sendData.append(channelNum)
    sendData.extend(targetChannel.getTimeStamp())
    sendData = dataGenerator(sendData)
    for client in clientList:
        socketSend(client, sendData)

def respDataLengthProcessor(data):
    targetChannel = None
    if data[1] == 0:
        targetChannel = channel_1
    elif data[1] == 1:
        targetChannel = channel_2
    else:
        log("The channel you selected not been supported", ERROR)
        return None

    try:
        for i in range(64):
            targetChannel.IDDataLength[i] = data[i + 2]
    except Exception as e:
        log("The amount of IDs witch define the data field is wrong", ERROR)
        log(e, ERROR)
        return None

    return dataGenerator(bytearray(b'\x80\x15'))

def LINBuadProcessor(data):
    targetChannel = None
    if data[1] == 0:
        targetChannel = channel_1
    elif data[1] == 1:
        targetChannel = channel_2
    else:
        log("The channel you selected not been supported", ERROR)
        return None

    targetChannel.busBuad = int.from_bytes(data[2: 6], byteorder='little')

    sendData = bytearray(b'\x93')
    sendData.append(data[1])
    sendData.append(targetChannel.LINPolicyVer)
    sendData.extend(targetChannel.errorCount.to_bytes(2, byteorder='little'))
    sendData.extend(targetChannel.busBuad.to_bytes(4, byteorder='little'))
    return dataGenerator(sendData)

def dataGenerator(data):
    resData = bytearray(b'\x68')
    dataLen = len(data)
    dataLen = dataLen.to_bytes(2, byteorder='little')
    resData.extend(dataLen)
    resData.extend(data)
    resData.append(getSumCheck(resData))
    resData.append(0x16)
    return resData